package org.saintandreas.serket.test; import java.io.File; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.MulticastSocket; import java.net.SocketAddress; import java.net.SocketException; import java.net.SocketTimeoutException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Random; import java.util.ResourceBundle; import java.util.Set; import java.util.UUID; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.HttpException; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.servlet.DefaultServlet; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.ToolTip; import org.eclipse.swt.widgets.Tray; import org.eclipse.swt.widgets.TrayItem; import org.saintandreas.serket.impl.av.SerketConnectionManager; import org.saintandreas.serket.impl.av.SerketContentDirectory; import org.saintandreas.serket.impl.av.SerketIcon; import org.saintandreas.serket.impl.av.SerketMediaServer; import org.saintandreas.serket.impl.didl.file.FileContainer; import org.saintandreas.serket.impl.servlet.DescriptionServlet; import org.saintandreas.serket.impl.servlet.FetchServlet; import org.saintandreas.serket.impl.servlet.UpnpServiceServlet; import org.saintandreas.serket.service.Service; import org.saintandreas.serket.ssdp.Message; import org.saintandreas.serket.ssdp.SSDP; import org.saintandreas.serket.ssdp.SSDPServer; import org.saintandreas.util.NetUtil; import org.saintandreas.util.ThreadUtil; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class IntegrationTest { private static final Log LOG = LogFactory.getLog(IntegrationTest.class); private static final ResourceBundle resources = ResourceBundle.getBundle("serket"); private final ExecutorService executor = Executors.newCachedThreadPool(); private final String uuid; private final SerketMediaServer mediaServer; private final SerketContentDirectory cd; private final SerketConnectionManager cm; private final Server jettyServer; private final SSDPServer ssdpServer; private final ConfigurableApplicationContext context; public class HandlerFactory implements SSDPServer.HandlerFactory { @Override public org.saintandreas.serket.ssdp.SSDPServer.Handler buildHandler(DatagramPacket packet) { return new Handler(packet); } } public void handleSearchMessage(DatagramPacket packet, Message searchRequest) throws IOException { LOG.trace("handling message " + searchRequest.usn); int wait = Integer.valueOf(searchRequest.headers.get("MX").getValue().trim()); ThreadUtil.safeSleep(new Random().nextInt(wait * 1000)); Map<String, String> nts = new HashMap<String, String>(); nts.put(uuid, uuid); nts.put("upnp:rootdevice", uuid + "::" + "upnp:rootdevice"); nts.put(mediaServer.getDeviceType(), uuid + "::" + mediaServer.getDeviceType()); for (Service s : mediaServer.getServiceList()) { nts.put(s.getServiceType(), uuid + "::" + s.getServiceType()); } LOG.trace("Sending alive messages"); String location = "http://" + NetUtil.getInet4Address().getHostAddress() + ":8080/description/"; DatagramSocket socket = new DatagramSocket(); // socket.connect(packet.getSocketAddress()); for (Map.Entry<String, String> entry : nts.entrySet()) { String message = Message.buildSearchResponseMessage(entry.getValue(), entry.getKey(), location, 1800, "serketLib/0.1"); DatagramPacket outPacket = SSDP.getPacket(message); outPacket.setSocketAddress(packet.getSocketAddress()); socket.send(outPacket); } } public static Set<String> URL_SET = new HashSet<String>(); public class Handler extends SSDPServer.Handler { public Handler(DatagramPacket packet) { super(packet); } @Override public void run() { try { Message message = Message.parseMessage(packet); switch (message.type) { case NOTIFY_ALIVE: case NOTIFY_UPDATE: String url = message.headers.get("LOCATION").getValue(); if (!URL_SET.contains(url)) { synchronized (URL_SET){ if (URL_SET.add(url)) { LOG.warn(url); } } } break; case SEARCH: { if (message.usn.startsWith(uuid)) { handleSearchMessage(this.packet, message); } else { for (String s : SSDPServer.SEARCH_RESPONSE_IDS) { if (message.usn.equals(s)) { handleSearchMessage(this.packet, message); break; } } } break; } } } catch (HttpException e) { LogFactory.getLog(getClass()).warn(e); } catch (IOException e) { LogFactory.getLog(getClass()).warn(e); } } } public IntegrationTest() { uuid = "uuid:" + UUID.randomUUID().toString(); context = new ClassPathXmlApplicationContext("test-context.xml"); mediaServer = new SerketMediaServer(uuid, "/ui"); mediaServer.getServiceList().add(cd = new SerketContentDirectory("/service/cd/control", "/service/cd/event")); FileContainer fc = new FileContainer(cd.getRootContainer(), new File("c:\\media")); cd.getRootContainer().addChild(fc); mediaServer.getServiceList().add(cm = new SerketConnectionManager("/service/cm/control", "/service/cm/event")); mediaServer.getIconList().add(new SerketIcon("image/png", "/images/Play1Hot_256.png", 256, 256, 24)); jettyServer = new Server(8080); ssdpServer = new SSDPServer(executor, new HandlerFactory()); initJetty(); } public void start() throws Exception { ssdpServer.listen(); jettyServer.start(); executor.submit(new Sender()); SSDP.sendDiscover(); } public void stop() throws Exception { jettyServer.stop(); jettyServer.join(); executor.shutdownNow(); } public void initJetty() { List<org.eclipse.jetty.server.Handler> handlerList = new ArrayList<org.eclipse.jetty.server.Handler>(); // the raw file resource handler { ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); context.setContextPath("/images"); context.setBaseResource(Resource.newClassPathResource("/images/")); context.addServlet(new ServletHolder(new DefaultServlet()), "/*"); handlerList.add(context); } // the service descriptor handler { ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); context.setContextPath("/scpd"); context.setBaseResource(Resource.newClassPathResource("/scpd/")); context.addServlet(new ServletHolder(new DefaultServlet()), "/*"); handlerList.add(context); } // the description handler { ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); context.setContextPath("/description"); context.addServlet(new ServletHolder(new DescriptionServlet(mediaServer)), "/*"); handlerList.add(context); } // the content access handler { ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); context.setContextPath("/fetch"); context.addServlet(new ServletHolder(new FetchServlet()), "/*"); handlerList.add(context); } // the content directory handler { ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); context.setContextPath("/service"); UpnpServiceServlet servlet = new UpnpServiceServlet(); servlet.getServices().add(cd); servlet.getServices().add(cm); context.addServlet(new ServletHolder(servlet), "/*"); handlerList.add(context); } // the service descriptor handler { ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); context.setContextPath("/"); context.addServlet(new ServletHolder(new LoggingServlet()), "/*"); handlerList.add(context); } ContextHandlerCollection contexts = new ContextHandlerCollection(); contexts.setHandlers(handlerList.toArray(new org.eclipse.jetty.server.Handler[] {})); jettyServer.setHandler(contexts); } protected class Sender implements Runnable { @Override public void run() { try { MulticastSocket socket = new MulticastSocket(); while (!executor.isShutdown()) { try { List<String> nts = new ArrayList<String>(); nts.add("upnp:rootdevice"); nts.add(mediaServer.getDeviceType()); for (Service s : mediaServer.getServiceList()) { nts.add(s.getServiceType()); } LOG.trace("Sending alive messages"); for (String s : nts) { String message = Message.buildNotifyAliveMessage(s, uuid + "::" + s, "http://" + NetUtil.getInet4Address().getHostAddress() + ":8080/description/", 60 * 60, "serketLib/0.1"); socket.send(SSDP.getPacket(message)); } Thread.sleep(5000); } catch (SocketTimeoutException e) { continue; } } } catch (Exception e) { } } } private static Shell openShell(Display display) { final Shell shell = new Shell(display); shell.setVisible(false); // shell.setText(resources.getString("Window_title")); // shell.setSize(500, 300); // shell.open(); final ToolTip tip = new ToolTip(shell, SWT.BALLOON | SWT.ICON_INFORMATION); tip.setMessage("Balloon Message Goes Here!"); Image image = new Image(display, IntegrationTest.class.getResourceAsStream("/images/Play1Hot_256.png")); Tray tray = display.getSystemTray(); if (tray != null) { TrayItem item = new TrayItem(tray, SWT.NONE); final Menu menu = new Menu(shell, SWT.POP_UP); item.setImage(image); item.setToolTip(tip); item.addListener(SWT.MenuDetect, new org.eclipse.swt.widgets.Listener() { public void handleEvent(Event event) { menu.setVisible(true); } }); { MenuItem menuItem = new MenuItem(menu, SWT.PUSH); menuItem.setText(resources.getString("Config_menuitem")); } new MenuItem(menu, SWT.SEPARATOR); { MenuItem menuItem = new MenuItem(menu, SWT.PUSH); menuItem.setText(resources.getString("Exit_menuitem")); menuItem.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { shell.close(); } }); } } return shell; } public static void main(String[] args) throws Exception { IntegrationTest app = new IntegrationTest(); app.start(); Display display = new Display(); Shell shell = openShell(display); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } display.dispose(); app.stop(); } } // XmlConfiguration configuration = new XmlConfiguration(new // File("myJetty.xml").toURL()); // configuration.configure(server); // server.start(); // //@Override //public void run() { //}